mysql

您所在的位置:网站首页 mysql s1009 mysql

mysql

2023-08-29 02:29| 来源: 网络整理| 查看: 265

在进行数据查询时,控制台报了Caused by: com.mysql.cj.exceptions.WrongArgumentException: HOUR_OF_DAY: 0 -> 1异常,查询得知:这是由于查mysql库,转换类型为datetime类型的字段引起的。

网上的解决方案有多种,大多数都是通过设置时区来解决的,但遗憾的是通过测试我发现即使在将数据跑在时区正确的数据库上,在执行起来我这仍然出错。

最后发现我的问题出现在夏令时上。

夏令时

记得小时候过过几个夏令时,大概的意思就是在某一天把表调快1个小时,然后再到某一天把表再调慢1个小时。这直接造成的问题的是:xxxx年xx月xx日会对应上两个时间戳。比如我们假设把表调慢的那一天是2021年10月4日的12点。具体的操作是当时钟第一次经过2021年10月4日12点时,我们把表调到2021年10月4日11点。所以在2021年10月4日11点至12点,我们会重新过一次。

关于时间这块,曾经回达到一个时间戳为负的问题,也有那么点意思:https://segmentfault.com/q/1010000038248983,赶兴趣的可以看看。

那么问题来了,比我们记录用户的出生时间,精确到分钟。如果这个人录入的是2021年10月4日11点20分,那我们的系统没有办法来准确的判断这个时间是第一个11点20分,还是过1小时后的第二个11点20分。

夏令时,还给我们带来的另一个问题。有些时间是对应不上时间戳的。再比如我们设置在2021年5月1日0时,将表调快1时,则在历史上不会出现2021年5月1日0时至1时的时间,所以如果我们统计出生时间点,用户写的是:2021年5月1日0时30分,则该数据必须是个假数据。

排查

夏令时讲完后,我们讲下排查过程。其实并不是所有的数据在查询时,都会报这种异常,所以要把那个特殊的点找出来,这里给一种最笨的展示方法:

boolean last = false; int page = 0; Pageable pageable = PageRequest.of(page, 1); while (!last) { try { Page residents = this.residentRepository.findAll(specification, pageable); page++; pageable = PageRequest.of(page, 1); last = residents.isLast(); } catch (Exception e) { last = true; e.printStackTrace(); this.logger.info("当前页" + pageable.getPageNumber()); } }

最终控制台打印信息:2021-11-04 13:25:38.562 INFO 4226 --- [nio-8081-exec-7] c.y.s.service.ResidentServiceImpl : 当前页1089

然后我们去数据表中把这条记录查出来:

select * FROM resident limit 1089, 1

我们发现此人的出生日期是1947年4月15日0时0分0分。其实这个日期用户仅仅是输入了1947-4-15,只是我们存的时候自动添加了0时0分0秒。但恰巧,这个数字对应的时间戳,它恰恰就是一个无效数字。

测试代码如下:

@Test void time() { Calendar calendar = Calendar.getInstance(); // 启用严格检查模式 calendar.setLenient(false); calendar.set(1947, 3, 15, 0, 0, 0); System.out.println(calendar.getTime()); }

异常内容:java.lang.IllegalArgumentException: HOUR_OF_DAY: 0 -> 1它是在说:你说自己是0点出生的,但是本JAVA大牛查了一下,1947年4月15日就没有0点,当天的最小值是1点。

解决问题

问题找到了,解决便是最简单的一环。

找到报错的历史数据,将0点改成8点。找到历史的代码,将0点改成8点。 public static Timestamp getTimeStampFormIdNumber(String idNumber) { // 进行出生日期赋值 int year = Integer.valueOf(idNumber.substring(6, 10)); int month = Integer.valueOf(idNumber.substring(10, 12)); int day = Integer.valueOf(idNumber.substring(12, 14)); Calendar calendar = Calendar.getInstance(); - calendar.set(year, month - 1, day, 0, 0, 0); + calendar.set(year, month - 1, day, 12, 0, 0); return new Timestamp(calendar.getTimeInMillis()); }

至于为什么改成12点,是由于我发现夏令时的修改(调快或调慢)都规避了12点,所以时间为12点,则可以有效避免无效时间戳的问题.当然了,你还可以改成13点,只要不是凌晨的那几个小时,都没有什么问题。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3